#include <stdio.h>
#include <windows.h>

#define MAX_SECTIONS 0xF
#define MAX_IMPORTS 0xFF
#define MAX_DLL_FUNCTIONS 0x8F
#define MAX_FUNCTION_TEXT 0x1F

int main( int argc, char **argv ) {

  FILE *fp ;
  IMAGE_DOS_HEADER image_dos_header ;
  IMAGE_NT_HEADERS32 image_nt_headers32 ;
  IMAGE_SECTION_HEADER image_section_headers[ MAX_SECTIONS ] ;
  unsigned int i, j, k, is_idata, imports_num ;
  int idata_index, c, original_first_thunk ;
  char idata[] = { 0x2e, 0x69, 0x64, 0x61, 0x74, 0x61, 0x00, 0x00 } ;
  IMAGE_IMPORT_DESCRIPTOR image_import_descriptors[MAX_IMPORTS] ;
  char dll_names[MAX_IMPORTS][MAX_FUNCTION_TEXT] ;
  char dll_functions[MAX_IMPORTS][MAX_DLL_FUNCTIONS][MAX_FUNCTION_TEXT] ;
  unsigned int dll_functions_address[MAX_IMPORTS][MAX_DLL_FUNCTIONS] ;
  int dll_nums[MAX_IMPORTS] ;
  DWORD thunk ;
  unsigned int address ;
 
  if( argc != 2 ) {
    printf( "usage : %s <filename>\n", argv[ 0 ] ) ;
    return -1 ;
  }

  if( ! ( fp = fopen( argv[ 1 ], "rb" ) ) ) {
    printf( "failed to open input file.\n" ) ;
    return -1 ;
  }

  if( ! fread( &image_dos_header, sizeof( image_dos_header ), 1, fp ) ) {
    printf( "failed to read input file.\n" ) ;
    return -1 ;
  }
  if( fseek( fp, image_dos_header.e_lfanew, SEEK_SET ) ) {
    printf( "failed to seek input file.\n" ) ;
    return -1 ;
  }
  if( ! fread( &image_nt_headers32, sizeof( image_nt_headers32 ), 1, fp ) ) {
    printf( "failed to read input file.\n" ) ;
    return -1 ;
  }

  if( ! fread( image_section_headers, sizeof( image_section_headers[0] ), image_nt_headers32.FileHeader.NumberOfSections, fp ) ) {
    printf( "failed to read input file.\n" ) ;
    return -1 ;
  }

  idata_index = -1 ;
  for( i = 0; i < image_nt_headers32.FileHeader.NumberOfSections; i++ ) {
    is_idata = 1 ;
    for( j = 0; j < 8; j++ ) {
      if( idata[j] != (char)image_section_headers[i].Name[j] ) {
        is_idata = 0 ;
      }
    }
    if( is_idata ) {
      idata_index = i ;
    }
  }

  imports_num = 0 ;
  if( idata_index != -1 ) {
    if( fseek( fp, image_section_headers[idata_index].PointerToRawData, SEEK_SET ) ) {
      printf( "failed to seek input file.\n" ) ;
      return -1 ;
    }
    for( i = 0; i < MAX_IMPORTS; i++ ) {
      if( ! fread( &image_import_descriptors[i], sizeof( image_import_descriptors[0] ), 1, fp ) ) {
        printf( "failed to read input file.\n" ) ;
        return -1 ;
      }
      if( image_import_descriptors[i].Characteristics == 0 &&
          image_import_descriptors[i].TimeDateStamp == 0 &&
          image_import_descriptors[i].ForwarderChain == 0 &&
          image_import_descriptors[i].Name == 0 &&
          image_import_descriptors[i].FirstThunk == 0 ) {
        break ;
      }
      imports_num++ ;
    }
  }

  for( i = 0; i < imports_num; i++ ) {

    if( fseek( fp, image_import_descriptors[i].Name - image_section_headers[idata_index].VirtualAddress + image_section_headers[idata_index].PointerToRawData, SEEK_SET ) ) {
      printf( "failed to seek input file.\n" ) ;
      return -1 ;
    }

    j = 0 ;
    while( ( c = getc( fp ) ) != EOF ) {
      if( c == 0 ) {
        break ; 
      }
      dll_names[i][j] = (char) c ;
      j++ ;
    }

    original_first_thunk = image_import_descriptors[i].OriginalFirstThunk - image_section_headers[idata_index].VirtualAddress + image_section_headers[idata_index].PointerToRawData ;
    j = 0 ;
    while( 1 ) {
      if( fseek( fp, original_first_thunk + sizeof( DWORD ) * j, SEEK_SET ) ) {
        printf( "failed to seek input file.\n" ) ;
        return -1 ;
      }
      if( ! fread( &thunk, sizeof( DWORD ), 1, fp ) ) {
        printf( "failed to read input file.\n" ) ;
        return -1 ;
      }
      if( thunk == 0 ) {
        break ;
      }

      if( fseek( fp, thunk - image_section_headers[idata_index].VirtualAddress + image_section_headers[idata_index].PointerToRawData + 2, SEEK_SET ) ) {
        printf( "failed to seek input file.\n" ) ;
        return -1 ;
      }

      k = 0 ;
      dll_functions_address[i][j] = thunk - image_section_headers[idata_index].VirtualAddress + image_section_headers[idata_index].PointerToRawData + 2 ;
      while( ( c = getc( fp ) ) != EOF ) {
        if( c == 0 ) {
          break ;
        }
        dll_functions[i][j][k] = (char) c ;
        k++ ;
      }
      j++ ;
    }
    dll_nums[i] = j ;
  }
 
  fclose( fp ) ;


  if( image_dos_header.e_magic != 0x5a4d || image_nt_headers32.Signature != 0x4550 ) {
    printf( "input file is not PE.\n" ) ;
    return 1 ;
  }

  address = 0 ;

  printf( "*IMAGE_DOS_HEADER\n" ) ;
  printf( " e_magic    : %04X [%.2s] <%06X>\n", image_dos_header.e_magic, &image_dos_header.e_magic, address ) ;
  address += sizeof( image_dos_header.e_magic ) ;
  printf( " e_cblp     : %04X      <%06X>\n", image_dos_header.e_cblp, address ) ;
  address += sizeof( image_dos_header.e_cblp ) ;
  printf( " e_cp       : %04X      <%06X>\n", image_dos_header.e_cp, address ) ;
  address += sizeof( image_dos_header.e_cp ) ;
  printf( " e_crlc     : %04X      <%06X>\n", image_dos_header.e_crlc, address ) ;
  address += sizeof( image_dos_header.e_crlc ) ;
  printf( " e_cparhdr  : %04X      <%06X>\n", image_dos_header.e_cparhdr, address ) ;
  address += sizeof( image_dos_header.e_cparhdr ) ;
  printf( " e_minalloc : %04X      <%06X>\n", image_dos_header.e_minalloc, address ) ;
  address += sizeof( image_dos_header.e_minalloc ) ;
  printf( " e_maxalloc : %04X      <%06X>\n", image_dos_header.e_maxalloc, address ) ;
  address += sizeof( image_dos_header.e_maxalloc ) ;
  printf( " e_ss       : %04X      <%06X>\n", image_dos_header.e_ss, address ) ;
  address += sizeof( image_dos_header.e_ss ) ;
  printf( " e_sp       : %04X      <%06X>\n", image_dos_header.e_sp, address ) ;
  address += sizeof( image_dos_header.e_sp ) ;
  printf( " e_csum     : %04X      <%06X>\n", image_dos_header.e_csum, address ) ;
  address += sizeof( image_dos_header.e_csum ) ;
  printf( " e_ip       : %04X      <%06X>\n", image_dos_header.e_ip, address ) ;
  address += sizeof( image_dos_header.e_ip ) ;
  printf( " e_cs       : %04X      <%06X>\n", image_dos_header.e_cs, address ) ;
  address += sizeof( image_dos_header.e_cs ) ;
  printf( " e_lfarlc   : %04X      <%06X>\n", image_dos_header.e_lfarlc, address ) ;
  address += sizeof( image_dos_header.e_lfarlc ) ;
  printf( " e_ovno     : %04X      <%06X>\n", image_dos_header.e_ovno, address ) ;
  address += sizeof( image_dos_header.e_ovno ) ;
  printf( " e_res[4]   :" ) ;
  for( i = 0; i < 4; i++ ) {
    printf( " %04X", image_dos_header.e_res[i] ) ;
  }
  printf( " <%06X>\n", address ) ;
  address += sizeof( image_dos_header.e_res[0] ) * 4 ;
  printf( " e_oemid    : %04X      <%06X>\n", image_dos_header.e_oemid, address ) ;
  address += sizeof( image_dos_header.e_oemid ) ;
  printf( " e_oeminfo  : %04X      <%06X>\n", image_dos_header.e_oeminfo, address ) ;
  address += sizeof( image_dos_header.e_oeminfo ) ;
  printf( " e_res2[10] :" ) ;
  for( i = 0; i < 10; i++ ) {
    printf( " %04X", image_dos_header.e_res2[i] ) ;
  }
  printf( " <%06X>\n", address ) ;
  address += sizeof( image_dos_header.e_res2[0] ) * 10 ;
  printf( " e_lfanew   : %08X  <%06X>\n", image_dos_header.e_lfanew, address ) ;
  address = image_dos_header.e_lfanew ;

  printf( "*IMAGE_NT_HEADERS32\n" ) ;
  printf( " Signature  : %08X [%.2s] <%06X>\n", image_nt_headers32.Signature, &image_nt_headers32.Signature, address ) ;
  address += sizeof( image_nt_headers32.Signature ) ;

  printf( "**IMAGE_FILE_HEADER\n" ) ;
  printf( "  Machine              : %04X     <%06X>\n", image_nt_headers32.FileHeader.Machine, address ) ;
  address += sizeof( image_nt_headers32.FileHeader.Machine ) ;
  printf( "  NumberOfSections     : %04X     <%06X>\n", image_nt_headers32.FileHeader.NumberOfSections, address ) ;
  address += sizeof( image_nt_headers32.FileHeader.NumberOfSections ) ;
  printf( "  TimeDateStamp        : %08X <%06X>\n", image_nt_headers32.FileHeader.TimeDateStamp, address ) ;
  address += sizeof( image_nt_headers32.FileHeader.TimeDateStamp ) ;
  printf( "  PointerToSymbolTable : %08X <%06X>\n", image_nt_headers32.FileHeader.PointerToSymbolTable, address ) ;
  address += sizeof( image_nt_headers32.FileHeader.PointerToSymbolTable ) ;
  printf( "  NumberOfSymbols      : %08X <%06X>\n", image_nt_headers32.FileHeader.NumberOfSymbols, address ) ;
  address += sizeof( image_nt_headers32.FileHeader.NumberOfSymbols ) ;
  printf( "  SizeOfOptionalHeader : %04X     <%06X>\n", image_nt_headers32.FileHeader.SizeOfOptionalHeader, address ) ;
  address += sizeof( image_nt_headers32.FileHeader.SizeOfOptionalHeader ) ;
  printf( "  Characteristics      : %04X     <%06X>\n", image_nt_headers32.FileHeader.Characteristics, address ) ;
  address += sizeof( image_nt_headers32.FileHeader.Characteristics ) ;

  printf( "**IMAGE_OPTIONAL_HEADER\n" ) ;
  printf( "  Magic                       : %04X     <%06X>\n", image_nt_headers32.OptionalHeader.Magic, address ) ;
  address += sizeof( image_nt_headers32.OptionalHeader.Magic ) ;
  printf( "  MajorLinkerVersion          : %02X       <%06X>\n", image_nt_headers32.OptionalHeader.MajorLinkerVersion, address ) ;
  address += sizeof( image_nt_headers32.OptionalHeader.MajorLinkerVersion ) ;
  printf( "  MinorLinkerVersion          : %02X       <%06X>\n", image_nt_headers32.OptionalHeader.MinorLinkerVersion, address ) ;
  address += sizeof( image_nt_headers32.OptionalHeader.MinorLinkerVersion ) ;
  printf( "  SizeOfCode                  : %08X <%06X>\n", image_nt_headers32.OptionalHeader.SizeOfCode, address ) ;
  address += sizeof( image_nt_headers32.OptionalHeader.SizeOfCode ) ;
  printf( "  SizeOfInitializedData       : %08X <%06X>\n", image_nt_headers32.OptionalHeader.SizeOfInitializedData, address ) ;
  address += sizeof( image_nt_headers32.OptionalHeader.SizeOfInitializedData ) ;
  printf( "  SizeOfUninitializedData     : %08X <%06X>\n", image_nt_headers32.OptionalHeader.SizeOfUninitializedData, address ) ;
  address += sizeof( image_nt_headers32.OptionalHeader.SizeOfUninitializedData ) ;
  printf( "  AddressOfEntryPoint         : %08X <%06X>\n", image_nt_headers32.OptionalHeader.AddressOfEntryPoint, address ) ;
  address += sizeof( image_nt_headers32.OptionalHeader.AddressOfEntryPoint ) ;
  printf( "  BaseOfCode                  : %08X <%06X>\n", image_nt_headers32.OptionalHeader.BaseOfCode, address ) ;
  address += sizeof( image_nt_headers32.OptionalHeader.BaseOfCode ) ;
  printf( "  BaseOfData                  : %08X <%06X>\n", image_nt_headers32.OptionalHeader.BaseOfData, address ) ;
  address += sizeof( image_nt_headers32.OptionalHeader.BaseOfData ) ;
  printf( "  ImageBase                   : %08X <%06X>\n", image_nt_headers32.OptionalHeader.ImageBase, address ) ;
  address += sizeof( image_nt_headers32.OptionalHeader.ImageBase ) ;
  printf( "  SectionAlignment            : %08X <%06X>\n", image_nt_headers32.OptionalHeader.SectionAlignment, address ) ;
  address += sizeof( image_nt_headers32.OptionalHeader.SectionAlignment ) ;
  printf( "  FileAlignment               : %08X <%06X>\n", image_nt_headers32.OptionalHeader.FileAlignment, address ) ;
  address += sizeof( image_nt_headers32.OptionalHeader.FileAlignment ) ;
  printf( "  MajorOperatingSystemVersion : %04X     <%06X>\n", image_nt_headers32.OptionalHeader.MajorOperatingSystemVersion, address ) ;
  address += sizeof( image_nt_headers32.OptionalHeader.MajorOperatingSystemVersion ) ;
  printf( "  MinorOperatingSystemVersion : %04X     <%06X>\n", image_nt_headers32.OptionalHeader.MinorOperatingSystemVersion, address ) ;
  address += sizeof( image_nt_headers32.OptionalHeader.MinorOperatingSystemVersion ) ;
  printf( "  MajorImageVersion           : %04X     <%06X>\n", image_nt_headers32.OptionalHeader.MajorImageVersion, address ) ;
  address += sizeof( image_nt_headers32.OptionalHeader.MajorImageVersion ) ;
  printf( "  MinorImageVersion           : %04X     <%06X>\n", image_nt_headers32.OptionalHeader.MinorImageVersion, address ) ;
  address += sizeof( image_nt_headers32.OptionalHeader.MinorImageVersion ) ;
  printf( "  MajorSubsystemVersion       : %04X     <%06X>\n", image_nt_headers32.OptionalHeader.MajorSubsystemVersion, address ) ;
  address += sizeof( image_nt_headers32.OptionalHeader.MajorSubsystemVersion ) ;
  printf( "  MinorSubsystemVersion       : %04X     <%06X>\n", image_nt_headers32.OptionalHeader.MinorSubsystemVersion, address ) ;
  address += sizeof( image_nt_headers32.OptionalHeader.MinorSubsystemVersion ) ;
  printf( "  Win32VersionValue           : %08X <%06X>\n", image_nt_headers32.OptionalHeader.Win32VersionValue, address ) ;
  address += sizeof( image_nt_headers32.OptionalHeader.Win32VersionValue ) ;
  printf( "  SizeOfImage                 : %08X <%06X>\n", image_nt_headers32.OptionalHeader.SizeOfImage, address ) ;
  address += sizeof( image_nt_headers32.OptionalHeader.SizeOfImage ) ;
  printf( "  SizeOfHeaders               : %08X <%06X>\n", image_nt_headers32.OptionalHeader.SizeOfHeaders, address ) ;
  address += sizeof( image_nt_headers32.OptionalHeader.SizeOfHeaders ) ;
  printf( "  CheckSum                    : %08X <%06X>\n", image_nt_headers32.OptionalHeader.CheckSum, address ) ;
  address += sizeof( image_nt_headers32.OptionalHeader.CheckSum ) ;
  printf( "  Subsystem                   : %04X     <%06X>\n", image_nt_headers32.OptionalHeader.Subsystem, address ) ;
  address += sizeof( image_nt_headers32.OptionalHeader.Subsystem ) ;
  printf( "  DllCharacteristics          : %04X     <%06X>\n", image_nt_headers32.OptionalHeader.DllCharacteristics, address ) ;
  address += sizeof( image_nt_headers32.OptionalHeader.DllCharacteristics ) ;
  printf( "  SizeOfStackReserve          : %08X <%06X>\n", image_nt_headers32.OptionalHeader.SizeOfStackReserve, address ) ;
  address += sizeof( image_nt_headers32.OptionalHeader.SizeOfStackReserve ) ;
  printf( "  SizeOfStackCommit           : %08X <%06X>\n", image_nt_headers32.OptionalHeader.SizeOfStackCommit, address ) ;
  address += sizeof( image_nt_headers32.OptionalHeader.SizeOfStackCommit ) ;
  printf( "  SizeOfHeapReserve           : %08X <%06X>\n", image_nt_headers32.OptionalHeader.SizeOfHeapReserve, address ) ;
  address += sizeof( image_nt_headers32.OptionalHeader.SizeOfHeapReserve ) ;
  printf( "  SizeOfHeapCommit            : %08X <%06X>\n", image_nt_headers32.OptionalHeader.SizeOfHeapCommit, address ) ;
  address += sizeof( image_nt_headers32.OptionalHeader.SizeOfHeapCommit ) ;
  printf( "  LoaderFlags                 : %08X <%06X>\n", image_nt_headers32.OptionalHeader.LoaderFlags, address ) ;
  address += sizeof( image_nt_headers32.OptionalHeader.LoaderFlags ) ;
  printf( "  NumberOfRvaAndSizes         : %08X <%06X>\n", image_nt_headers32.OptionalHeader.NumberOfRvaAndSizes, address ) ;
  address += sizeof( image_nt_headers32.OptionalHeader.NumberOfRvaAndSizes ) ;

  for( i = 0; i < 16; i++ ) {
    printf( "**DataDirectory[%d]\n", i ) ;
    printf( "  VirtualAddress              : %08X <%06X>\n", image_nt_headers32.OptionalHeader.DataDirectory[i].VirtualAddress, address ) ;
    address += sizeof( image_nt_headers32.OptionalHeader.DataDirectory[i].VirtualAddress, address ) ;
    printf( "  Size                        : %08X <%06X>\n", image_nt_headers32.OptionalHeader.DataDirectory[i].Size, address ) ;
    address += sizeof( image_nt_headers32.OptionalHeader.DataDirectory[i].Size ) ;
  }

  for( i = 0; i < image_nt_headers32.FileHeader.NumberOfSections; i++ ) {
    printf( "*IMAGE_SECTION_HEADER[%d]\n", i ) ;
    printf( " Name[8]              :" ) ;
    for( j = 0; j < 8; j++ ) {
      printf( " %02X", image_section_headers[i].Name[j] ) ;
    }
    printf( " [%.8s] <%06X>\n", &image_section_headers[i].Name, address ) ;
    address += sizeof( image_section_headers[i].Name[0] ) * 8 ;
    printf( " PhysicalAddress      : %08X <%06X>\n", image_section_headers[i].Misc.PhysicalAddress, address ) ;
    printf( " VirtualSize          : %08X <%06X>\n", image_section_headers[i].Misc.VirtualSize, address ) ;
    address += sizeof( image_section_headers[i].Misc.PhysicalAddress ) ;
    printf( " VirtualAddress       : %08X <%06X>\n", image_section_headers[i].VirtualAddress, address ) ;
    address += sizeof( image_section_headers[i].VirtualAddress ) ;
    printf( " SizeOfRawData        : %08X <%06X>\n", image_section_headers[i].SizeOfRawData, address ) ;
    address += sizeof( image_section_headers[i].SizeOfRawData ) ;
    printf( " PointerToRawData     : %08X <%06X>\n", image_section_headers[i].PointerToRawData, address ) ;
    address += sizeof( image_section_headers[i].PointerToRawData ) ;
    printf( " PointerToRelocations : %08X <%06X>\n", image_section_headers[i].PointerToRelocations, address ) ;
    address += sizeof( image_section_headers[i].PointerToRelocations ) ;
    printf( " PointerToLinenumbers : %08X <%06X>\n", image_section_headers[i].PointerToLinenumbers, address ) ;
    address += sizeof( image_section_headers[i].PointerToLinenumbers ) ;
    printf( " NumberOfRelocations  : %04X     <%06X>\n", image_section_headers[i].NumberOfRelocations, address ) ;
    address += sizeof( image_section_headers[i].NumberOfRelocations ) ;
    printf( " NumberOfLinenumbers  : %04X     <%06X>\n", image_section_headers[i].NumberOfLinenumbers, address ) ;
    address += sizeof( image_section_headers[i].NumberOfLinenumbers ) ;
    printf( " Characteristics      : %08X <%06X>\n", image_section_headers[i].Characteristics, address ) ;
    address += sizeof( image_section_headers[i].Characteristics ) ;
  }

  if( idata_index != -1 ) {
    for( i = 0; i < imports_num; i++ ) {
      address = image_section_headers[idata_index].PointerToRawData + sizeof( image_import_descriptors[i] ) * i ;
      printf( "*IMAGE_IMPORT_DESCRIPTOR[%d] <%s>\n", i, dll_names[i] ) ;
      printf( " Characteristics    : %04X [%04X] <%06X>\n", image_import_descriptors[i].Characteristics, image_import_descriptors[i].Characteristics - image_section_headers[idata_index].VirtualAddress + image_section_headers[idata_index].PointerToRawData, address ) ;
      printf( " OriginalFirstThunk : %04X [%04X] <%06X>\n", image_import_descriptors[i].OriginalFirstThunk, image_import_descriptors[i].OriginalFirstThunk - image_section_headers[idata_index].VirtualAddress + image_section_headers[idata_index].PointerToRawData, address ) ;
      address += sizeof( image_import_descriptors[i].Characteristics ) ;
      printf( " TimeDateStamp      : %04X        <%06X>\n", image_import_descriptors[i].TimeDateStamp, address ) ;
      address += sizeof( image_import_descriptors[i].TimeDateStamp ) ;
      printf( " ForwarderChain     : %04X        <%06X>\n", image_import_descriptors[i].ForwarderChain, address ) ;
      address += sizeof( image_import_descriptors[i].ForwarderChain ) ;
      printf( " Name               : %04X [%04X] <%06X>\n", image_import_descriptors[i].Name, image_import_descriptors[i].Name - image_section_headers[idata_index].VirtualAddress + image_section_headers[idata_index].PointerToRawData, address ) ;
      address += sizeof( image_import_descriptors[i].Name ) ;
      printf( " FirstThunk         : %04X [%04X] <%06X>\n", image_import_descriptors[i].FirstThunk, image_import_descriptors[i].FirstThunk - image_section_headers[idata_index].VirtualAddress + image_section_headers[idata_index].PointerToRawData, address ) ;
      address += sizeof( image_import_descriptors[i].FirstThunk ) ;
      printf( "   <functions>\n" ) ;
      for( j = 0; j < dll_nums[i]; j++ ) {
        printf( "    %-15s <%06X>\n", dll_functions[i][j], dll_functions_address[i][j] ) ;
      }

    }
  }

  return 0 ;

}

